#ifndef _PARTMANAGER
#define _PARTMANAGER

#include <Ogre.h>
#include <vector>
#include <hash_map>
#include "CoreManager.h"
#include "Core/Part.h"

#include <cppconn/resultset.h>


namespace Core
{
	class PartManager : public Ogre::Singleton<PartManager>
	{
	public:
		PartManager()
		{
			_getPartTypes();
			_getSubPartTypes();
		}
		void addPart(Part *prt)
		{
			char buffer[65];
			removePart(prt);
			mAvailableParts.insert(std::pair<ulong,Part *>(prt->getID(),prt));
			std::string str = "";
			str+="INSERT INTO parts(Name,Description,Type,SubType,HitPoints,CombatPoints,MeshFile) VALUES(";
			str+="'"+prt->getName()+"','"+prt->getDescriprion()+"','"+prt->getPartType()+"','"+prt->getPartSubType()
				+"','"+_ltoa(prt->getHitPoints(),buffer,10)+"','"+_ltoa(prt->getCombatPoints(),buffer,10)+"','"+prt->getEntity()->getMesh()->getName()+"');";
			getCoreManager()->writeSql(str);
			str="SELECT MAX(ID) from parts;";
			sql::ResultSet *res = getCoreManager()->readSql(str);
			while(res->next())
				prt->setID(res->getInt(1));
			delete res;
			//armor factor
			for (std::vector<String >::const_iterator itr = getCoreManager()->getDamageTypes()->begin();itr != getCoreManager()->getDamageTypes()->end();itr++)
			{
				str="";
				str+="INSERT INTO part_armor_factors(PartID,ArmorType,Factor) VALUES(";
				str+="'";
				str+=_ltoa(prt->getID(),buffer,10);
				str+="','";
				str+=itr->c_str();
				str+="','";
				str+=_ltoa(prt->getArmorByType(*itr),buffer,10);
				str+="');";
				getCoreManager()->writeSql(str);
			}
			//speed factor
			for (std::vector<String >::const_iterator itr = getCoreManager()->getTerrainTypes()->begin();itr != getCoreManager()->getTerrainTypes()->end();itr++)
			{
				str="";
				str+="INSERT INTO part_speed_factors(PartID,TerrainType,Factor) VALUES(";
				str+="'";
				str+=_ltoa(prt->getID(),buffer,10);
				str+="','";
				str+=itr->c_str();
				str+="','";
				str+=_ltoa(prt->getSpeedByTerrain(*itr),buffer,10);
				str+="');";
				getCoreManager()->writeSql(str);
			}
			//if Weapon
			if (prt->getPartType().compare("Weapon")==0)
			{
				for (std::vector<String >::const_iterator itr = getCoreManager()->getDamageTypes()->begin();itr != getCoreManager()->getDamageTypes()->end();itr++)
				{
					str="";
					str+="INSERT INTO part_damage_factors(PartID,DamageType,Factor) VALUES(";
					str+="'";
					str+=_ltoa(prt->getID(),buffer,10);
					str+="','";
					str+=itr->c_str();
					str+="','";
					str+=_ltoa(static_cast<Weapon*>(prt)->getDamageByType(*itr),buffer,10);
					str+="');";
					getCoreManager()->writeSql(str);
				}
			}
			//Technologies
			for (hash_map<int, Technology*>::const_iterator itr = prt->getTechnologies()->begin();itr !=  prt->getTechnologies()->end();itr++)
			{
				str="";
				str+="INSERT INTO part_technology(PartID,TechnologyID,Level) VALUES(";
				str+="'";
				str+=_ltoa(prt->getID(),buffer,10);
				str+="','";
				str+=_itoa(itr->first,buffer,10);
				str+="','";
				str+=_itoa(itr->second->getLevel(),buffer,10);
				str+="');";
				getCoreManager()->writeSql(str);
			}
			
		}
		void removePart(Part *prt)
		{
			mAvailableParts.erase(prt->getID());
		}
		void addPartType(String name)
		{
			mPartTypes.push_back(name);
		}
		void removePartType(String name)
		{
			for (std::vector<String >::iterator itr=mPartTypes.begin();itr!=mPartTypes.end();itr++)
				if (itr->compare(name))
				{
					mPartTypes.erase(itr);
					break;
				}
		}
		std::vector<String > *getPartTypes()
		{
			return &mPartTypes;
		}

		void addPartSubType(String name)
		{
			mPartSubTypes.push_back(name);
		}
		void removePartSubType(String name)
		{
			for (std::vector<String >::iterator itr=mPartSubTypes.begin();itr!=mPartSubTypes.end();itr++)
				if (itr->compare(name))
				{
					mPartSubTypes.erase(itr);
					break;
				}
		}
		std::vector<String > *getPartSubTypes()
		{
			return &mPartSubTypes;
		}

		//Part *getNextPart()
		//{
		//	//mPartIterator
		//	return *(++itr);
		//}

		static PartManager& getSingleton(void);
		static PartManager* getSingletonPtr(void);
	private:

		void _getPartTypes()
		{
			std::string str = "SELECT * FROM part_types;";
			sql::ResultSet *res = getCoreManager()->readSql(str);
			while (res->next())
				addPartType(res->getString(1));
			delete res;
		}
		void _getSubPartTypes()
		{
			std::string str = "SELECT * FROM part_sub_types;";
			sql::ResultSet *res = getCoreManager()->readSql(str);
			while (res->next())
				addPartSubType(res->getString(1));
			delete res;
		}

		std::vector<String > mPartTypes;
		std::vector<String > mPartSubTypes;
		stdext::hash_map<ulong,Part *> mAvailableParts;
		
		//std::vector<Part *>::iterator mPartIterator;
	};
}

using namespace Core;
template<> PartManager* Ogre::Singleton<PartManager>::ms_Singleton = 0;
PartManager* PartManager::getSingletonPtr(void)
{
    return ms_Singleton;
}
PartManager& PartManager::getSingleton(void)
{  
    assert( ms_Singleton );  return ( *ms_Singleton );  
}

#endif